/*
 * Copyright (c) 2019.  鼎捷软件股份有限公司.All rights reserved.
 */

package com.digiwin.dap.middleware.service.impl;

import com.digiwin.dap.middleware.entity.BaseEntity;
import com.digiwin.dap.middleware.entity.UnionKey;
import com.digiwin.dap.middleware.repository.BaseEntityRepository;
import com.digiwin.dap.middleware.service.EntityWithUnionKeyManagerService;
import com.digiwin.dap.middleware.exception.BusinessException;
import org.springframework.data.jpa.domain.Specification;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.List;
import java.util.Optional;

/**
 * 基于指定字段的业务主键的基础实体操作类
 *
 * @param <T>
 */
public abstract class BaseEntityWithUnionKeyManagerService<T extends BaseEntity>
        extends BaseEntityManagerService<T>
        implements EntityWithUnionKeyManagerService<T> {

    @PersistenceContext
    EntityManager entityManager;

    /**
     * 获取表对应的业务主键字段
     *
     * @return 业务主键
     */
    @Override
    public UnionKey getUnionKey() {
        if (unionKey == null) {
            unionKey = createUnionKey();
        }
        return unionKey;
    }

    /**
     * 派生类创建表对应的业务主键字段
     *
     * @return 业务主键
     */
    protected abstract UnionKey createUnionKey();

    private UnionKey unionKey;

    /**
     * 获取dao
     *
     * @return dao服务
     */
    @Override
    protected abstract BaseEntityRepository getRepository();

    /**
     * 根据unionkey获取sid
     *
     * @param values 业务主键对应的值，如果是空，传递null，数量必须和业务主键的数量一致，顺序也必须一致
     * @return sid 返回主键
     */
    @Override
    public long getSidByUnionKey(Object... values) {
        String whereSql = getUnionKey().getWhereSql(values);
        String sql = String.format("SELECT  SID FROM %s WHERE %s LIMIT 1", this.getMappingTableName(), whereSql);
        List resultList = entityManager.createNativeQuery(sql).getResultList();
        if (resultList.size() == 0){
            return 0;
        }
        return Long.valueOf(resultList.get(0).toString());
    }

    /**
     * 根据实体Id 和租户Id 查询实体
     *
     * @param values 租户Sid
     * @return 实体对象
     */
    @Override
    public T findByUnionKey(Object... values) {
        //TODO:使用lambda
        Optional result = this.getRepository().findOne(new Specification<T>() {
            @Override
            public Predicate toPredicate(Root<T> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                return getUnionKey().getSpecification(root, criteriaQuery, criteriaBuilder, values);
            }
        });
        if (result.isPresent()) {
            return (T) result.get();
        } else {
            return null;
        }
    }

    /**
     * 根据实体Id 和租户Id 删除实体
     *
     * @param values 业务逐渐对应的值
     */
    @Override
    public void deleteByUnionKey(Object... values) {
        String whereSql = getUnionKey().getWhereSql(values);
        String sql = String.format("DELETE FROM %s WHERE %s LIMIT 1", this.getMappingTableName(), whereSql);
        entityManager.createNativeQuery(sql).executeUpdate();

    }

    /**
     * 根据租户sid和id判断是否存在
     *
     * @param values 业务逐渐对应的值
     * @return true：存在
     */
    @Override
    public boolean existsByUnionKey(Object... values) {
        String whereSql = getUnionKey().getWhereSql(values);
        String sql = String.format("SELECT COUNT(SID) FROM %s WHERE %s LIMIT 1", this.getMappingTableName(), whereSql);
        Object result = entityManager.createNativeQuery(sql).getSingleResult();
        return result != null && Integer.valueOf(result.toString()) > 0;
    }

    /**
     * 启用
     *
     * @param values 业务逐渐对应的值
     */
    @Override
    public void enable(Object... values) {
        BaseEntity data = this.findByUnionKey(values);
        if (data != null) {
            data.setDisabled(false);
            this.getRepository().save(data);
        } else {
            throw new BusinessException("数据已经被删除.union key:" + values);
        }
    }

    /**
     * 禁用
     *
     * @param values 业务逐渐对应的值
     */
    @Override
    public void disable(Object... values) {
        BaseEntity data = this.findByUnionKey(values);
        if (data != null) {
            data.setDisabled(true);
            this.getRepository().save(data);
        } else {
            throw new BusinessException("数据已经被删除.union key:" + values);
        }
    }


}
